//
// Created by YueChuan on 2023/5/4.
//

#include "servlet.h"

namespace yuechuan {
    namespace http {
        FunctionServlet::FunctionServlet(callback cb) :
                Servlet("FunctionServlet"),
                m_cb(cb) {

        }

        int32_t FunctionServlet::handle(HttpRequest::ptr request, HttpResponse::ptr response,
                                        HttpSession::ptr session) {
            return m_cb(request, response, session);
        }

        ServletDispatch::ServletDispatch() :
                Servlet("ServletDispatch") {
            m_default.reset(new NotFoundServlet("yuechuan/1.0.0"));
        }

        int32_t ServletDispatch::handle(HttpRequest::ptr request, HttpResponse::ptr response,
                                        HttpSession::ptr session) {
            auto servlet = getMatchServlet(request->getPath());
            if (servlet) {
                servlet->handle(request, response, session);
            }
            return 0;
        }

        void ServletDispatch::addServlet(const std::string &uri, Servlet::ptr servlet) {
            RWMutexType::WriteLock lock(m_mutex);
            m_datas[uri] = std::make_shared<HoldServletCreator>(servlet);
        }

        void ServletDispatch::addServletCreator(const std::string &uri, IServletCreator::ptr creator) {
            RWMutexType::WriteLock lock(m_mutex);
            m_datas[uri] = creator;
        }

        void ServletDispatch::addGlobServletCreator(const std::string &uri, IServletCreator::ptr creator) {
            RWMutexType::WriteLock lock(m_mutex);
            for (auto it = m_globs.begin(); it != m_globs.end(); ++it) {
                if (it->first == uri) {
                    m_globs.erase(it);
                    break;
                }
            }
            m_globs.push_back(std::make_pair(uri, creator));
        }

        void ServletDispatch::addServlet(const std::string &uri, FunctionServlet::callback cb) {
            RWMutexType::WriteLock lock(m_mutex);
            m_datas[uri] = std::make_shared<HoldServletCreator>(std::make_shared<FunctionServlet>(cb));
        }

        void ServletDispatch::addGlobServlet(const std::string &uri, Servlet::ptr servlet) {
            RWMutexType::WriteLock lock(m_mutex);
            for (auto it = m_globs.begin(); it != m_globs.end(); ++it) {
                if (it->first == uri) {
                    m_globs.erase(it);
                    break;
                }
            }
            m_globs.push_back(std::make_pair(uri, std::make_shared<HoldServletCreator>(servlet)));
        }

        void ServletDispatch::addGlobServlet(const std::string &uri, FunctionServlet::callback cb) {
            return addGlobServlet(uri, std::make_shared<FunctionServlet>(cb));
        }

        void ServletDispatch::delServlet(const std::string &uri) {
            RWMutexType::WriteLock lock(m_mutex);
            m_datas.erase(uri);
        }

        void ServletDispatch::delGlobServlet(const std::string &uri) {
            RWMutexType::WriteLock lock(m_mutex);
            for (auto it = m_globs.begin();
                 it != m_globs.end(); ++it) {
                if (it->first == uri) {
                    m_globs.erase(it);
                    break;
                }
            }
        }

        Servlet::ptr ServletDispatch::getServlet(const std::string &uri) {
            RWMutexType::WriteLock lock(m_mutex);
            auto it = m_datas.find(uri);
            return it == m_datas.end() ? nullptr : it->second->get();
        }

        Servlet::ptr ServletDispatch::getGlobServlet(const std::string &uri) {
            RWMutexType::WriteLock lock(m_mutex);
            for (auto it = m_globs.begin(); it != m_globs.end(); ++it) {
                if (it->first == uri) {
                    return it->second->get();
                }
            }
            return nullptr;
        }

        Servlet::ptr ServletDispatch::getMatchServlet(const std::string &uri) {
            RWMutexType::WriteLock lock(m_mutex);
            auto mit = m_datas.find(uri);
            if (mit != m_datas.end()) {
                return mit->second->get();
            }
            for (auto it = m_globs.begin(); it != m_globs.end(); ++it) {
                if (!fnmatch(it->first.c_str(), uri.c_str(), 0)) {
                    return it->second->get();
                }
            }
            return m_default;
        }

        void ServletDispatch::listAllServletCreator(std::map<std::string, IServletCreator::ptr> &infos) {
            RWMutexType::ReadLock lock(m_mutex);
            for (auto it: m_datas) {
                infos[it.first] = it.second;
            }
        }

        void ServletDispatch::listAllGlobServletCreator(std::map<std::string, IServletCreator::ptr> &infos) {
            RWMutexType::ReadLock lock(m_mutex);
            for (auto &it : m_globs) {
                infos[it.first] = it.second;
            }
        }

        NotFoundServlet::NotFoundServlet(const std::string &name) :
                Servlet("NotFoundServlet"),
                m_name(name) {
            m_content = "<html>"
                        "<head>"
                        "<title>404 Not Found</title>"
                        "</head>"
                        "<body>"
                        "<center>"
                        "<h1>404 Not Found</h1>"
                        "</center>"
                        "<hr>"
                        "<center>" + name +
                        "</center>"
                        "</body>"
                        "</html>";
        }

        int32_t NotFoundServlet::handle(HttpRequest::ptr request, HttpResponse::ptr response,
                                        HttpSession::ptr session) {
            response->setStatus(HttpStatus::NOT_FOUND);
            response->setHeader("Server", "yuechuan/1.0");
            response->setHeader("Content-type", "text/html");
            response->setBody(m_content);
            return 0;
        }
    }
}